package practice

import (
	"fmt"
)

//注意defer的执行顺序与声明顺序相反.LIFO(last in first out)

/*
	//以下是比较通用的panic()和recover()的格式

	func main() {
    G()
    // 下面的代码会执行
    ...CODE IN MAIN...
	}
	func G(){
		defer func (){
			if str := recover(); str != nil {
				fmt.Println(str)
			}
		}()
		...CODE IN G()...

		// F()的调用必须在defer关键字之后
		F()
		// 该函数内下面的代码不会执行
		...CODE IN G()...
	}
	func F() {
		...CODE1...
		panic("error found")
		// 下面的代码不会执行
		...CODE IN F()...
	}
*/

/*
	package main

	import "fmt"

	func main() {
		println("start main")
		b()
		println("end main")	//会输出
	}

	func a() {
		println("start a")
		panic("panic in a")
		println("end a")	//没有输出
	}

	func b() {
		println("start b")
		defer func() {
			if str := recover(); str != nil {
				fmt.Println(str)
			}
		}()
		a()
		println("end b")	//没有输出
	}

	//结果输出:
	//start main
	//start b
	//start a
	//panic in a
	//end main

	//注意上面的end b、end a都没有被输出，但是end main输出了

*/

/*
	//defer func传值取值问题

	var x = 10
	func main() {
		a()
	}

	func a() {
		println("start a:",x)   // 输出10
		x = 20
		defer b(x)       // 压栈，并按值拷贝20到栈中.即defer函数调用时,就已经传递了参数了,只是代码暂未执行
		x = 30
		println("leaving a:",x)  // 输出30
		// 调用defer延迟的对象b()，输出20
	}

	func b(x int) {
		println("start b:",x)
	}
*/

/*
	//defer func传值取值问题

	var x = 10
	func main() {
		a()
	}

	func a() int {
		println("start a:", x) // 输出10
		x = 20
		defer func() {      // 压栈，但并未传值，所以内部引用x
			println("in defer:", x)  // 输出30
		}()
		x = 30
		println("leaving a:", x) // 输出30
		return x
	}
*/

func Main_defer_use() {
	/************ defer的使用 ************/
	fmt.Println(test()) //执行后输出:a d c b e

	//https://blog.csdn.net/woshiyuanlei/article/details/80052374
	/*
		本质原因是return xxx语句并不是一条原子指令，defer被插入到了赋值 与 RET之前，因此可能有机会改变最终的返回值
		return xxx会被改写成:
		 返回值 = xxx
		 调用defer函数
		 空的return
	*/
	fmt.Println(f())  //1
	fmt.Println(f1()) //5
	fmt.Println(f2()) //1
}

//defer会在函数执行完,这里是在return前执行,类似finally
//只有函数中全部defer执行完,这个函数test()才视为执行完成.test()称作外围函数
//当函数test()发生恐慌时,只有函数中所有defer执行完成,恐慌才会真正扩展至调用函数
//最终输出: a d c b e
func test() string {
	fmt.Println("a")

	//先定义的defer后执行
	defer func() {
		fmt.Println("b")
	}()

	//后定义的defer先执行
	defer func() {
		fmt.Println("c")
	}()

	fmt.Println("d")
	return "e" //所有defer执行完才会return
}

/*
	//f()函数可以改写为:
	func f() (result int) {
    result = 0 //return语句不是一条原子调用，return xxx其实是赋值＋RET指令
    func() { //defer被插入到return之前执行，也就是赋返回值和RET指令之间
        result++
    }()
    return
}
*/
//1
func f() (result int) { //命名的返回值(这里的result)是预先声明好的，在函数内部可以直接使用
	defer func() {
		result++
	}()
	return 0
}

/*
	//f1()函数可以改写为:
	func f1() (r int) {
    t := 5
    r = t //赋值指令
    func() { //defer被插入到赋值与返回之间执行，这个例子中返回值r没被修改过
        t = t + 5
    }
    return //空的return指令
}
*/
//5
func f1() (r int) {
	t := 5
	defer func() {
		t = t + 5
	}()
	return t
}

/*
	//f2()函数可以改写为:
	func f2() (r int) {
    r = 1 //给返回值赋值
    func(r int) { //这里改的r是传值传进去的r，不会改变要返回的那个r值
        r = r + 5
    }(r)
    return //空的return
}
*/
//1
func f2() (r int) {
	defer func(r int) {
		r = r + 5
	}(r)
	return 1
}
